import {Injectable} from '@angular/core';
import {
    HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpResponse,
    HttpErrorResponse
} from '@angular/common/http';
import {Observable} from "rxjs/Observable";
import 'rxjs/add/operator/do';
import {BASEURL} from "../../config/url.config";
import {debarUrl} from "../../config/debar-url.config";
import {NotInterceptUrls} from "../../config/url-notIntercept.config";
import {Events} from "ionic-angular";
import {ToastService} from "./toast.service";
import {HTTP} from "@ionic-native/http";
import {AdpMenuController} from "../../components/common/adp-menu/adp-menu.controller";
import {DeviceService} from '../native/device/device.service';
import {ConfigurationService} from './configuration.service';
import {JPush} from '@jiguang-ionic/jpush';
import {JPushControlerService} from "../native/push/jpush-controler.service";
import 'rxjs/add/operator/timeout';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/retry';
import 'rxjs/add/operator/repeat';

@Injectable()
export class HttpInterceptorService implements HttpInterceptor {

    constructor(private toastService: ToastService,
                private nativeHttp: HTTP,
                private menuCtrl: AdpMenuController,
                private events: Events,
                private jPush: JPush,
                private jPushControlerService: JPushControlerService,
                private configService: ConfigurationService,
                private deviceService: DeviceService) {
    }

    /**
     * 获取请求前缀
     * @param {HttpRequest<any>} req
     * @returns {string}
     */
    private getPrefixUrl(req: HttpRequest<any>): string {
        let prefixUrl: string = req.url;
        let x = debarUrl.filter((value) => {
            return req.url.indexOf(value) !== -1;
        });
        if (x.length === 0) {
            prefixUrl = BASEURL + req.url
        }
        return prefixUrl
    }

    /**
     * 判断不需要拦截的请求
     * @param {string | Request} url
     * @returns {boolean}
     */
    private isNotIntercept(url: string): boolean {
        let result = false;
        NotInterceptUrls.forEach(item => {
            if (url.indexOf(item) !== -1) {
                result = true;
            }
        });
        return result;
    }

    /**
     * 请求拦截
     * @param {HttpRequest<any>} req
     * @param {HttpHandler} next
     * @returns {Observable<HttpEvent<any>>}
     */
    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

        //请求开始时间
        const started: number = Date.now();
        //全局请求超时时间
        const timeout: number = 2*60*1000;

        let responseType = req.responseType;

        if (this.deviceService.isOnCordova()) {
            if (localStorage.getItem('JPushInit') !== 'OK') {
                this.jPush.init()
            }

            this.jPushControlerService.setRegistrationIDLocalStorage();
        }

        //设置请求头
        const uniqueHeader = req.headers
            .set('Authorization', this.getAuthorizationHeader())
            .set('device', this.deviceService.uuid());
        //拷贝出新的请求
        const authReq = req.clone({
            headers: uniqueHeader,
            url: this.getPrefixUrl(req)
        });

        //语言文件不需要拦截,url-notIntercept.config.ts中配置的不需要拦截
        if (req.url === './assets/i18n/zh.json' ||
            this.isNotIntercept(req.urlWithParams)
        ) {
            return next.handle(authReq).timeout(timeout).catch((err, caught) => {
                this.errorHandle(err);
                return caught.retry(0).repeat(0);
            });
        }

        let BasicUrl = BASEURL;
        let prefix = localStorage.getItem('prefix') || 'https://';


        switch (this.deviceService.isOnCordova() && BasicUrl.indexOf(prefix) !== -1) {
            case true: {

                this.nativeHttpHandle(authReq, responseType);

                return next
                    .handle(authReq)
                    .do(event => {
                        this.successHandle(req, event, started)
                    }, (err: HttpErrorResponse) => {
                        this.errorHandle(err);
                    }, () => {
                        this.completeHandle();
                    }).timeout(timeout).catch((err, caught) => {
                        this.errorHandle(err);
                        return caught.retry(0).repeat(0);
                    });//设置超时时间
            }
            case false: {
                return next
                    .handle(authReq)
                    .do(event => {
                        this.successHandle(req, event, started)
                    }, (err: HttpErrorResponse) => {
                        this.errorHandle(err);
                    }, () => {
                        this.completeHandle();
                    }).timeout(timeout).catch((err, caught) => {
                        this.errorHandle(err);
                        return caught.retry(0).repeat(0);
                    });//设置超时时间
            }
        }

    }

    private nativeHttpHandle(authReq: HttpRequest<any>, responseType: string): Observable<HttpEvent<any>> {
        this.nativeHttp.setDataSerializer('json');

        this.nativeHttp.setHeader('Authorization', this.getAuthorizationHeader());
        this.nativeHttp.setHeader('device', this.deviceService.uuid());
        // this.nativeHttp.setHeader('RegistrationID', this.jPushControlerService.getRegistrationIDLocalStorage());

        if (authReq.method === 'GET') {
            return Observable.create(observer => {
                this.nativeHttp.get(authReq.urlWithParams, {}, {})
                    .then(value => {
                        this.nativeHttpSuccess(observer, value, responseType);
                    }, reason => {
                        this.nativeHttpError(observer, reason, responseType)
                    })
            })
        }
        if (authReq.method === 'POST') {
            return Observable.create(observer => {
                this.nativeHttp.post(authReq.url, authReq.body, {})
                    .then(value => {
                        this.nativeHttpSuccess(observer, value, responseType);
                    }, reason => {
                        this.nativeHttpError(observer, reason, responseType)
                    })
            })
        }
        if (authReq.method === 'DELETE') {
            return Observable.create(observer => {
                this.nativeHttp.delete(authReq.url, {}, {})
                    .then(value => {
                        this.nativeHttpSuccess(observer, value, responseType);
                    }, reason => {
                        this.nativeHttpError(observer, reason, responseType)
                    })
            })
        }
        if (authReq.method === 'PUT') {
            return Observable.create(observer => {
                this.nativeHttp.put(authReq.url, authReq.body, {})
                    .then(value => {
                        this.nativeHttpSuccess(observer, value, responseType);
                    }, reason => {
                        this.nativeHttpError(observer, reason, responseType)
                    })
            })
        }
    }

    nativeHttpSuccess(observer, value, responseType) {

        console.log('Success', value);

        let res = new HttpResponse();
        let body = value.data;

        if (responseType === 'json') {
            body = JSON.parse(value.data)
        }

        observer.next(res.clone({
            body: body
        }));
        observer.complete();
    }

    nativeHttpError(observer, reason, responseType) {

        console.log('Error', reason);

        let error = reason.error;
        if (responseType === 'json') {
            error = JSON.parse(reason.error)
        }

        let httpErrorResponse: HttpErrorResponse = new HttpErrorResponse({
            error: error,
            status: reason.status
        });

        this.errorHandle(httpErrorResponse);
        observer.error(new HttpErrorResponse(httpErrorResponse));
        observer.complete();
    }

    /**
     * 成功回调
     * @param {HttpRequest<any>} req
     * @param event
     * @param {number} started
     */
    private successHandle(req: HttpRequest<any>, event, started: number) {
        if (event instanceof HttpResponse) {
        }
    }

    /**
     * http:error
     * @param {HttpErrorResponse} err
     */
    private errorHandle(err: HttpErrorResponse) {
        console.log(err);
        this.events.publish("http:error", err);
    }

    /**
     * 完成回调
     */
    private completeHandle() {

    }

    private getAuthorizationHeader(): string {
        const authorization = this.configService.personal.accessToken.value;
        if (authorization)
            return `Bearer ${authorization}`;
        else
            return '';
    }

}
